package com.engine.jucailinkq.attendance.attendanceanalysis.cmd.workovertime;

import com.engine.jucailinkq.attendance.enums.AccountingUnitEnum;
import com.engine.jucailinkq.attendance.enums.CheckBoxEnum;
import com.engine.jucailinkq.attendance.enums.DateTypeEnum;
import com.engine.jucailinkq.attendance.enums.DelayTypeEnum;
import com.engine.common.biz.AbstractCommonCommand;
import com.engine.common.entity.BizLogContext;
import com.engine.jucailinkq.common.util.DateUtil;
import com.engine.jucailinkq.common.util.DbTools;
import com.engine.jucailinkq.common.util.Utils;
import com.engine.core.interceptor.CommandContext;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import weaver.general.TimeUtil;
import weaver.general.Util;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 根据相关设置控制加班时长，并入库、加班转调休
 */
@Slf4j
public class SaveWorkOverTimeCmd extends AbstractCommonCommand<Map<String,Object>> {
    public SaveWorkOverTimeCmd(Map<String, Object> params) {
        this.params = params;
    }
    @Override
    public BizLogContext getLogContext() {
        return null;
    }

    @Override
    public Map<String, Object> execute(CommandContext commandContext) {

        //加班项目
        List<Map<String, Object>> workTimeBeLateItems = (List<Map<String,Object>>)params.get("workTimeBeLateItems");
        //加班时长
        double jbsc = Double.valueOf(params.get("jbsc").toString());
        //班次
        Map<String, Object> scheduleMap = (Map<String, Object>)params.get("scheduleMap");

        Map<String,Object> workOverTimeItems = Maps.newHashMap();


        //超出限制时长的处理方式
        String ccclfs = Util.null2String(workTimeBeLateItems.get(0).get("ccclfs"));
        //限制加班总长数
        String xzzjbsc = Util.null2String(workTimeBeLateItems.get(0).get("xzzjbsc"));
        //工作日加班最大小时数
        String rzdjbxss = Util.null2String(workTimeBeLateItems.get(0).get("rzdjbxss"));
        //每周最大加班小时数
        String yzdjbxss = Util.null2String(workTimeBeLateItems.get(0).get("yzdjbxss"));
        //每月最大加班小时数
        String zzdjbxss = Util.null2String(workTimeBeLateItems.get(0).get("zzdjbxss"));
        //加班时长自动转入假期余额
        String jbzdzjqye= Util.null2String(workTimeBeLateItems.get(0).get("jbzdzjqye"));
        //最小加班分钟数
        String jbqsfzs = Util.null2String(workTimeBeLateItems.get(0).get("jbqsfzs"));
        //超出最小时长后的单次累加分钟数
        String ccqszhdhsfzs = Util.null2String(workTimeBeLateItems.get(0).get("ccqszhdhsfzs"));
        //核算量
        double workOverTimeHsl = Double.valueOf(Util.null2String(workTimeBeLateItems.get(0).get("hsl")));
        //核算单位
        String workOverTimeHsdw = Util.null2String(workTimeBeLateItems.get(0).get("hsdw"));
        //分析日期
        String analysisDate = Util.null2String(params.get("analysisDate"));
        //实际开始时间
        String realityStartTime = Util.null2String(params.get("realityStartTime"));
        //实际结束时间
        String realityEndime = Util.null2String(params.get("realityEndime"));
        //考勤项目
        List<Map<String,Object>> attendanceItems = (List<Map<String,Object>>)params.get("attendanceItems");
        //不需要入加班结果和假期余额
        String notNeedInsertResult  = Util.null2String(params.get("realityEndime"));

        long diffdays = Long.valueOf(Util.null2String(params.get("diffdays")));



        String rqlx = Util.null2String(scheduleMap.get("rqlx"));

        List<Map<String, Object>> workOverTimeResults = null;

        String userId = Util.null2String(params.get("userId"));

        Map<String,Object> resultMap = Maps.newHashMap();

        if ((params.get("beSplit") == null || !(boolean)params.get("beSplit")) && xzzjbsc.equals(CheckBoxEnum.CHECKED.getKey())){
            if (!"".equals(jbqsfzs)){
                if (jbsc < Integer.valueOf(jbqsfzs)){
                    //小于最小加班分钟数不算加班
                    workOverTimeItems.put("item",workTimeBeLateItems.get(0).get("key"));
                    workOverTimeItems.put("itemduration","0");
                    return workOverTimeItems;
                }else if (jbsc >= Integer.valueOf(jbqsfzs) && !"".equals(ccqszhdhsfzs)){

                    jbsc = Double.valueOf(Utils.getItemdurationDown(Integer.valueOf(ccqszhdhsfzs), AccountingUnitEnum.MINUTES.getKey(),Double.valueOf(jbsc).intValue()-Integer.valueOf(jbqsfzs),AccountingUnitEnum.MINUTES)).intValue()+Integer.valueOf(jbqsfzs);
                }
            }
            if (jbsc <= 0 || "".equals(realityStartTime) || "".equals(realityEndime)){
                //加班时长为0
                workOverTimeItems.put("item",workTimeBeLateItems.get(0).get("key"));
                workOverTimeItems.put("itemduration","0");
                return workOverTimeItems;
            }


            //自动扣除
            if ("2".equals(ccclfs) && workOverTimeResults == null){
                String startDate = analysisDate.split("-")[0]+"-"+ analysisDate.split("-")[1]+"-01";
                String endDate = analysisDate.split("-")[0]+"-"+ analysisDate.split("-")[1]+"-"+diffdays;
                workOverTimeResults =getWorkOverTimeResults(DateUtil.beforeDay(startDate,7),DateUtil.AfterDay(endDate,7),userId);

            }
            if ("2".equals(ccclfs) && !"".equals(rzdjbxss) && (DateTypeEnum.WORK_DAY.getKey().equals(rqlx) || DateTypeEnum.CHANGECLASS.getKey().equals(rqlx))){
                //工作日加班最大数
                double maxDayTime = Double.valueOf(rzdjbxss) *60;
                if (jbsc > maxDayTime){
                    jbsc = maxDayTime;
                }
            }
            if ("2".equals(ccclfs) && !"".equals(zzdjbxss)){
                //每周最大加班小时数
                double weekTime = getWeekTime(workOverTimeResults,analysisDate);
                double maxWeekTime = Double.valueOf(zzdjbxss) *60;
                double time = jbsc+weekTime;
                if (time > maxWeekTime){
                    jbsc = maxWeekTime-weekTime;
                }
                if (jbsc <0){
                    jbsc = 0;
                }
            }
            if ("2".equals(ccclfs) && !"".equals(yzdjbxss)){
                //每月最大加班数
                double monthTime = getMonthTime(workOverTimeResults,analysisDate);
                double maxMonthTime = Double.valueOf(yzdjbxss) *60;
                double time = jbsc+monthTime;
                if (time > maxMonthTime){
                    jbsc = maxMonthTime-monthTime;
                }
            }
        }
        if (jbsc <0){
            jbsc = 0;
        }

        log.debug("最终加班时长: {}",jbsc);
        workOverTimeItems.put("item",workTimeBeLateItems.get(0).get("key"));
        double itemduration = Utils.getItemdurationDown(workOverTimeHsl,workOverTimeHsdw,Long.valueOf(Math.round(jbsc)).intValue(),AccountingUnitEnum.MINUTES);
        workOverTimeItems.put("itemduration",itemduration);
        workOverTimeItems.put("jbsc",jbsc);

        /**
         * 是否是有出勤结果
         */
        String sql = "select id from uf_jcl_kq_cqjg where ygid=? and rq=?";
        List<Map<String,Object>> dataList = DbTools.getSqlToList(sql,userId,analysisDate);
        String id = dataList.size()>0?Util.null2String(dataList.get(0).get("id")):"";
        /**
         * 入加班结果表
         */
        Map<String,Object> insertParam = Maps.newHashMap();
        insertParam.put("jbry",userId);
        insertParam.put("sjksrq",realityStartTime.split(" ")[0]);
        insertParam.put("sjkssj",realityStartTime.split(" ")[1]);
        insertParam.put("sjjsrq",realityEndime.split(" ")[0]);
        insertParam.put("sjjssj",realityEndime.split(" ")[1]);
        if (scheduleMap.get("overtimePlanId") != null){
            insertParam.put("jbjhid",scheduleMap.get("overtimePlanId"));
        }
        insertParam.put("sjjbsc",itemduration);
        insertParam.put("jbjgly","4");
        insertParam.put("jblx",workTimeBeLateItems.get(0).get("key"));
        insertParam.put("lyid",userId+"-"+ DateUtil.getCurrentDate());
        insertParam.put("zt","1");
        insertParam.put("eddxsc",0);
        insertParam.put("edjxsc",0);
        insertParam.put("ydxsc",0);
        insertParam.put("wdxsc",0);
        insertParam.put("jbgzrq",params.get("jbgzrq"));
        /**
         * 入假期余额
         */
        //加班时长自动转入假期余额
        resultMap.put("overTimeHoliday",Maps.newHashMap());
        if (CheckBoxEnum.CHECKED.getKey().equals(jbzdzjqye)){
            Map<String,Object> insertHoliDayParam = Maps.newHashMap();
            insertHoliDayParam.put("ygid",userId);
            insertHoliDayParam.put("jqid",workTimeBeLateItems.get(0).get("zrdjb"));
            insertHoliDayParam.put("lyid",userId+"-"+DateUtil.getCurrentDate());
            insertHoliDayParam.put("lylx","4");
            insertHoliDayParam.put("lyjblx",workTimeBeLateItems.get(0).get("key"));
            Map<String,Object> holidayItem = getHolidayItem(workTimeBeLateItems.get(0).get("zrdjb").toString(),attendanceItems);

            double ktsc = Utils.getItemdurationDown(Double.valueOf(holidayItem.get("hsl").toString()),holidayItem.get("hsdw").toString(),Double.valueOf(jbsc).intValue(),AccountingUnitEnum.MINUTES);

            insertHoliDayParam.put("ktsc",ktsc);
            insertHoliDayParam.put("yxsc",0);
            insertHoliDayParam.put("wxsc",ktsc);
            insertHoliDayParam.put("ztsc",0);
            insertHoliDayParam.put("jxsc",0);
            insertHoliDayParam.put("yqsc",0);
            insertHoliDayParam.put("yqyxsc",0);
            insertHoliDayParam.put("zfsc",0);

            insertParam.put("eddxsc",itemduration);
            insertParam.put("wdxsc",itemduration);

            //转入的假期额度生效日期
            String yesxrq = Util.null2String(workTimeBeLateItems.get(0).get("yesxrq"));
            if ("0".equals(yesxrq)){
                //一月后
                insertHoliDayParam.put("sxrq",DateUtil.lastMonth(analysisDate,DateUtil.yyyyMMdd));
            }else if ("1".equals(yesxrq)){
                //次月
                insertHoliDayParam.put("sxrq",DateUtil.lastMonth(analysisDate)+"-01");
            }else if ("2".equals(yesxrq)){
                //次日
                insertHoliDayParam.put("sxrq",DateUtil.AfterDay(analysisDate,1));
            }
            //额度可用的周期
            String yekyzq = Util.null2String(workTimeBeLateItems.get(0).get("yekyzq"));
            if ("0".equals(yekyzq)){
                //一个月
                insertHoliDayParam.put("jzrq",DateUtil.nextMonth(insertHoliDayParam.get("sxrq").toString(),1,DateUtil.yyyyMMdd));
            }else if ("1".equals(yekyzq)){
                //两个月
                insertHoliDayParam.put("jzrq",DateUtil.nextMonth(insertHoliDayParam.get("sxrq").toString(),2,DateUtil.yyyyMMdd));
            }else if ("2".equals(yekyzq)){
                //三个月
                insertHoliDayParam.put("jzrq",DateUtil.nextMonth(insertHoliDayParam.get("sxrq").toString(),3,DateUtil.yyyyMMdd));
            }else if ("3".equals(yekyzq)){
                //六个月
                insertHoliDayParam.put("jzrq",DateUtil.nextMonth(insertHoliDayParam.get("sxrq").toString(),6,DateUtil.yyyyMMdd));
            }else if ("4".equals(yekyzq)){
                //十二个月
                insertHoliDayParam.put("jzrq",DateUtil.nextMonth(insertHoliDayParam.get("sxrq").toString(),12,DateUtil.yyyyMMdd));
            }else if ("5".equals(yekyzq)){
                //当前季度
                insertHoliDayParam.put("jzrq",DateUtil.getCurrentQuarter(insertHoliDayParam.get("sxrq").toString()));
            }else if ("6".equals(yekyzq)){
                //当前半年
                insertHoliDayParam.put("jzrq",DateUtil.getCurrentHalfYear(insertHoliDayParam.get("sxrq").toString()));
            }else if ("7".equals(yekyzq)){
                //当前一年
                insertHoliDayParam.put("jzrq",insertHoliDayParam.get("sxrq").toString().split("-")[0]+"-12-31");
            }

            String zdyqsc = Util.null2String(workTimeBeLateItems.get(0).get("zdyqsc"));
            insertHoliDayParam.put("yqsxrq",insertHoliDayParam.get("jzrq"));
            if (DelayTypeEnum.ONE_MONTH.getKey().equals(zdyqsc)){
                //一个月
                insertHoliDayParam.put("yqsxrq",DateUtil.nextMonth(insertHoliDayParam.get("jzrq").toString(),1,DateUtil.yyyyMMdd));
            }else if (DelayTypeEnum.TWO_MONTH.getKey().equals(zdyqsc)){
                //两个月
                insertHoliDayParam.put("yqsxrq",DateUtil.nextMonth(insertHoliDayParam.get("jzrq").toString(),2,DateUtil.yyyyMMdd));
            }else if (DelayTypeEnum.THREE_MONTH.getKey().equals(zdyqsc)){
                //三个月
                insertHoliDayParam.put("yqsxrq",DateUtil.nextMonth(insertHoliDayParam.get("jzrq").toString(),3,DateUtil.yyyyMMdd));
            }else if (DelayTypeEnum.HALF_YEAR.getKey().equals(zdyqsc)){
                //半年
                insertHoliDayParam.put("yqsxrq",DateUtil.nextMonth(insertHoliDayParam.get("jzrq").toString(),6,DateUtil.yyyyMMdd));
            }else if (DelayTypeEnum.ONE_YEAR.getKey().equals(zdyqsc)){
                //一年
                insertHoliDayParam.put("yqsxrq",DateUtil.nextMonth(insertHoliDayParam.get("jzrq").toString(),12,DateUtil.yyyyMMdd));
            }
            resultMap.put("overTimeHoliday",getholidayResult(id,insertHoliDayParam));
        }
        resultMap.put("overTimeResult",getOverTimeResult(id,insertParam));
        resultMap.put("workOverTimeItems",workOverTimeItems);
        return resultMap;
    }

    public List<Map<String, Object>> getWorkOverTimeResults(String startDate,String endDate,String userId){
        String sql = "select a.sjjbsc,a.sjksrq,a.sjjsrq,a.jblx,b.hsl,b.hsdw from uf_jcl_kq_jbjg a left join uf_jcl_kq_kqxm b on a.jblx=b.id where jbry=? and sjksrq>=? and sjjsrq<=?";
        List<Map<String, Object>> dataList = DbTools.getSqlToList(sql,userId,startDate,endDate);
        return dataList;
    }
    /**
     * 获得工作日加班数
     * @param dataList
     * @return
     */
    public int getWorkDayTime(List<Map<String, Object>> dataList,String date){
        List<Map<String, Object>> list = dataList.stream().filter(e->date.equals(e.get("sjksrq"))).collect(Collectors.toList());
        int totalHour = list.stream().mapToInt(e->Integer.valueOf(e.get("sjjbsc").toString())).sum();
        return totalHour;
    }
    /**
     * 获得一周加班数
     * @param dataList
     * @return
     */
    public double getWeekTime(List<Map<String, Object>> dataList,String date){
        int day = TimeUtil.getDayOfWeek(date);
        if (day ==0){
            day = 7;
        }
        String startDate = DateUtil.beforeDay(date,day-1);
        String endDate = DateUtil.AfterDay(date,7-day);
        List<Map<String, Object>> list = dataList.stream().filter(e->{
            String sjksrq = Util.null2String(e.get("sjksrq"));
            if (DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(startDate)) >=0 &&
                    DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(endDate)) <=0  &&
                    DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(date)) !=0){
                return true;
            }else {
                return false;
            }
        }).collect(Collectors.toList());
        double totalMinute = 0;
        for (Map<String, Object> data:list){
            String hsdw = data.get("hsdw").toString();
            totalMinute += Utils.getItemduration(1,AccountingUnitEnum.MINUTES.getKey(), Double.valueOf(data.get("sjjbsc").toString()),AccountingUnitEnum.getEnum(hsdw),8);
        }

        return totalMinute;
    }
    /**
     * 获得一个月加班数
     * @param dataList
     * @return
     */
    public double getMonthTime(List<Map<String, Object>> dataList,String date){
        String startDate = date.split("-")[0]+"-"+ date.split("-")[1]+"-01";
        String endDate = date.split("-")[0]+"-"+ date.split("-")[1]+"-"+Util.null2String(params.get("diffdays"));
        List<Map<String, Object>> list = dataList.stream().filter(e->DateUtil.getTime(e.get("sjksrq").toString()).compareTo(DateUtil.getTime(startDate))>=0 &&
                DateUtil.getTime(e.get("sjjsrq").toString()).compareTo(DateUtil.getTime(endDate))<=0).collect(Collectors.toList());

        double totalMinute = 0;
        for (Map<String, Object> data:list){
            String hsdw = data.get("hsdw").toString();
            totalMinute += Utils.getItemduration(1,AccountingUnitEnum.MINUTES.getKey(), Double.valueOf(data.get("sjjbsc").toString()),AccountingUnitEnum.getEnum(hsdw),8);
        }
        return totalMinute;
    }

    /**
     * 更新加班结果
     */
    public Map<String,Object> getOverTimeResult(String lyid, Map<String,Object> insertParam){
        if (!"".equals(lyid)){
            String sql = "select edjxsc,ydxsc from uf_jcl_kq_jbjg where lyid=?";
            List<Map<String,Object>> overTimeResultList = DbTools.getSqlToList(sql,lyid);
            if (overTimeResultList.size() > 0){
                Map<String,Object> overTimeResult = overTimeResultList.get(0);
                insertParam.put("edjxsc",overTimeResult.get("edjxsc"));
                insertParam.put("ydxsc",overTimeResult.get("ydxsc"));
                double eddxsc = Utils.convertDouble(insertParam.get("eddxsc"));
                double ydxsc = Utils.convertDouble(overTimeResult.get("ydxsc"));
                insertParam.put("wdxsc",String.format("%.2f",eddxsc-ydxsc));
            }
        }
        return insertParam;
        //Utils.InsertFormTable("uf_jcl_kq_jbjg",insertParam,(Map<String,String>)params.get("formmodeIdMap"));

    }
    /**
     * 更新假期余额
     * 当假期余额为0不记录假期余额，如果当天已有该加班的假期余额记录则更新。
     */
    public Map<String,Object> getholidayResult(String lyid,Map<String,Object> insertParam){
        double ktsc = Utils.convertDouble(insertParam.get("ktsc"));
        if (!"".equals(lyid)) {
//            String sql = "select yxsc,ztsc,zfsc,jxsc,yqsc,yqyxsc from uf_jcl_kq_jqye where lyid=?";
//            List<Map<String,Object>> holidayList = DbTools.getSqlToList(sql,lyid);
//            if (holidayList.size() > 0){
//                Map<String,Object> holidayMap = holidayList.get(0);
//                insertParam.put("yxsc",holidayMap.get("yxsc"));
//                insertParam.put("ztsc",holidayMap.get("ztsc"));
//                insertParam.put("zfsc",holidayMap.get("zfsc"));
//                insertParam.put("jxsc",holidayMap.get("jxsc"));
//                insertParam.put("yqsc",holidayMap.get("yqsc"));
//                insertParam.put("yqyxsc",holidayMap.get("yqyxsc"));
//                double wxsc = ktsc-Utils.convertDouble(insertParam.get("yxsc"))-Utils.convertDouble(holidayMap.get("ztsc"))-Utils.convertDouble(holidayMap.get("zfsc"));
//                insertParam.put("wxsc",String.format("%.2f",wxsc));
//            }
//            else {
//                if (ktsc == 0){
//                    insertParam.put("lyid",lyid);
//                }
//            }
         //   Utils.InsertFormTable("uf_jcl_kq_jqye",insertParam,(Map<String,String>)params.get("formmodeIdMap"));
        }
//        else {
//            if (ktsc !=0){
//                Utils.InsertFormTable("uf_jcl_kq_jqye",insertParam,(Map<String,String>)params.get("formmodeIdMap"));
//            }
//        }
        return insertParam;

    }

    public Map<String,Object> getHolidayItem(String holidayId,List<Map<String,Object>> attendanceItems){
        List<Map<String,Object>> holidayList = attendanceItems.stream().filter(e->e.get("key").equals(holidayId)).collect(Collectors.toList());
        if (holidayList.size() > 0){
            return holidayList.get(0);
        }else {
            String sql = "select hsl,hsdw from uf_jcl_kq_kqxm where id=?";
            holidayList = DbTools.getSqlToList(sql,holidayId);
            return holidayList.get(0);
        }
    }

    /**
     * 处理透支余额
     */
    public void handleOverdraftHoliday(List<Map<String,Object>> beforeHolidayBalanceList,double beforewxsc,List<Map<String,Object>> dataList){

        String updatesql = "update uf_jcl_kq_jqye set wxsc=0,yxsc=ktsc where id=?";

        //上一笔假透支归0
        DbTools.update(updatesql,beforeHolidayBalanceList.get(0).get("id"));
        //修改请假申请明细的假期余额字段将透支的假改成当前的
        String currentHolidayId = dataList.get(0).get("id").toString();

        String beforeHolidayId = beforeHolidayBalanceList.get(0).get("id").toString();

        String sql = "select id,glrq,sysc from uf_jcl_kq_qjjl_dt2 where jqye=? order by id desc";
        List<Map<String,Object>> askforleaveList = DbTools.getSqlToList(sql,beforeHolidayId);
        BigDecimal overdraftHoliday = new BigDecimal(String.valueOf(Math.abs(beforewxsc)));
        List<String> ids = Lists.newArrayList();
        for (Map<String,Object> askforleave:askforleaveList){
            BigDecimal sysc = new BigDecimal(askforleave.get("sysc").toString());
            overdraftHoliday = overdraftHoliday.subtract(sysc,new MathContext(2, RoundingMode.HALF_UP));
            if (overdraftHoliday.doubleValue() >= 0){
                ids.add(askforleave.get("id").toString());
            }
        }
        log.info("need adjust askforleave detail2 data : [{}]",ids);
        if (ids.size() > 0){
            updatesql = "update uf_jcl_kq_qjjl_dt2 set jqye=? where id in ("+String.join(",",ids)+")";
            DbTools.update(updatesql,currentHolidayId);
        }
    }

}
